package goiot.api;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import com.fasterxml.jackson.core.type.TypeReference;

import goiot.GoiotHttp;
import goiot.MyParameterizedType;
import goiot.dto.JsonResp;
import goiot.dto.PageQuery;
import goiot.dto.PageResult;

/**
 * 增删改查api
 * 
 * @param <T>
 */
public abstract class CurdApi<T> {

	public static final TypeReference<JsonResp<Void>> VOID_RESP = new TypeReference<JsonResp<Void>>() {};

	protected TypeReference<JsonResp<PageResult<T>>> pageRef;
	
	protected TypeReference<JsonResp<T>> entityRef;
	
	protected final Type[] actualTypeArguments;

	protected CurdApi() {
		Type superClass = getClass().getGenericSuperclass();
		if (superClass instanceof Class<?>) { // sanity check, should never happen
			throw new IllegalArgumentException(
					"Internal error: TypeReference constructed without actual type information");
		}
		/*
		 * 22-Dec-2008, tatu: Not sure if this case is safe -- I suspect it is possible
		 * to make it fail? But let's deal with specific case when we know an actual use
		 * case, and thereby suitable workarounds for valid case(s) and/or error to
		 * throw on invalid one(s).
		 */
		actualTypeArguments = ((ParameterizedType) superClass).getActualTypeArguments();
		
		pageRef = new TypeReference<JsonResp<PageResult<T>>>() {
			@Override
			public Type getType() {
				return new MyParameterizedType(JsonResp.class, new Type[] {new MyParameterizedType(PageResult.class, actualTypeArguments)});
			}
		};
		entityRef = new TypeReference<JsonResp<T>>() {
			@Override
			public Type getType() {
				return new MyParameterizedType(JsonResp.class, actualTypeArguments);
			}
		};
	}

	protected abstract String getFullPath(String path);

	/**
	 * 分页查询
	 * 
	 * @param query
	 * @return
	 */
	public JsonResp<PageResult<T>> page(PageQuery query) {
		JsonResp<PageResult<T>> post = GoiotHttp.post(getFullPath("/page"), query, pageRef);
		return post;
	}

	/**
	 * 新增
	 * 
	 * @param data
	 * @return
	 */
	public JsonResp<Void> add(Object data) {
		JsonResp<Void> resp = GoiotHttp.post(getFullPath(""), data, VOID_RESP);
		return resp;
	}

	/**
	 * 修改
	 * 
	 * @param data
	 * @return
	 */
	public JsonResp<Void> update(Object data) {
		JsonResp<Void> resp = GoiotHttp.put(getFullPath(""), data, VOID_RESP);
		return resp;
	}

	/**
	 * 单个查询
	 * 
	 * @param id
	 * @return
	 */
	public JsonResp<T> get(Object id) {
		JsonResp<T> jsonResp = GoiotHttp.get(getFullPath("/" + id), entityRef);
		return jsonResp;
	}

	/**
	 * 删除
	 * 
	 * @param id
	 * @return
	 */
	public JsonResp<Void> delete(Object id) {
		JsonResp<Void> resp = GoiotHttp.delete(getFullPath("/" + id), null, VOID_RESP);
		return resp;
	}
}
